package com.axon.components.controls {
  import com.axon.base.helpers.AxUtils;
  import com.axon.components.containers.AxPanel;
  import com.axon.components.containers.AxTitleWindowSizeable;
  import com.axon.components.events.AxListEvent;
  import com.axon.dataservices.helpers.AxDSUtils;

  import flash.display.DisplayObjectContainer;
  import flash.events.Event;
  import flash.events.KeyboardEvent;
  import flash.events.MouseEvent;
  import flash.ui.Keyboard;

  import mx.controls.AdvancedDataGrid;
  import mx.events.CollectionEvent;
  import mx.events.CollectionEventKind;
  import mx.events.FlexEvent;
  import mx.events.ListEvent;

  import org.restfulx.collections.ModelsCollection;
  import org.restfulx.models.RxModel;

  [Event(name="axChange",type="com.axon.components.events.AxListEvent")] // name must be equal to AxonListEvent.SELECTION_CHANGE 
  [Event(name="axDefaultGesture",type="com.axon.components.events.AxListEvent")] // name must be equal to AxonListEvent.DEFAULT_GESTURE

  public class AxDataGrid extends AdvancedDataGrid {
    private var fNeedColumsWidthAdjust:Boolean = false;

    private var _lastSelectedId:String = "";

    private var _lastSelectedIndex:int = -1;

    //////////////////////////////////////////////////////////////////////////////////////////////////////

    [Inspectable(category="Other")]
    public var axHandleDefaultAction:Boolean = true;

    //////////////////////////////////////////////////////////////////////////////////////////////////////

    public function AxDataGrid() {
      super();
      doubleClickEnabled = true;
      addEventListener(Event.RESIZE, onResize);
      addEventListener(FlexEvent.CREATION_COMPLETE, onResize);
      addEventListener(ListEvent.CHANGE, onChange);
      addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
      addEventListener(MouseEvent.DOUBLE_CLICK, onDoubleClick);
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////

    override public function set dataProvider(value:Object):void {
      if (value == dataProvider)
        return;

      super.dataProvider = value;

      if ((dataProvider) && (dataProvider is ModelsCollection))
        ModelsCollection(dataProvider).addEventListener(CollectionEvent.COLLECTION_CHANGE, onCollectionChange);

      dispatchEvent(new AxListEvent(AxListEvent.SELECTION_CHANGE));
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////

    override public function set selectedItem(value:Object):void {
      super.selectedItem = value;
      memorizeLastSelection();
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////

    override public function set selectedIndex(value:int):void {
      super.selectedIndex = value;
      memorizeLastSelection();
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////

    public function get axLastSelectedId():String {
      return _lastSelectedId;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////

    override protected function commitProperties():void {
      axAdjustColumnWidthts();
      super.commitProperties();
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////

    private function onResize(event:Event):void {
      fNeedColumsWidthAdjust = true;
      invalidateSize();
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////

    private function onChange(event:Event):void {
      memorizeLastSelection();
      dispatchEvent(new AxListEvent(AxListEvent.SELECTION_CHANGE));
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////

    private function onCollectionChange(event:CollectionEvent):void {

      if ((event.kind == CollectionEventKind.REMOVE) && (dataProvider is ModelsCollection)) {

        var lenght:int = (dataProvider as ModelsCollection).length;

        if (_lastSelectedIndex == lenght)
          _lastSelectedIndex--;
        selectedIndex = _lastSelectedIndex;
      }
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////

    protected function onKeyDown(event:KeyboardEvent):void {
      var theParent:DisplayObjectContainer;

      //  Escape

      if (event.charCode == Keyboard.ESCAPE) {
        theParent = parent;

        while ((theParent != null) && !(theParent is AxPanel) && !(theParent is AxTitleWindowSizeable))
          theParent = theParent.parent;

        if (theParent != null)
          theParent.dispatchEvent(event.clone());
      }

      // Space

      else if ((event.charCode == Keyboard.SPACE) && selectedItem) {
        axPerformDefaultGesture();
      }
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////

    protected function onDoubleClick(event:MouseEvent):void {
      axPerformDefaultGesture();
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////

    public function axPerformDefaultGesture():void {
      if (selectedItem)
        dispatchEvent(new AxListEvent(AxListEvent.DEFAULT_GESTURE));
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////

    public function axSelectItemWithId(id:String):int {
      var index:int = -1;

      if (dataProvider is ModelsCollection)
        index = ModelsCollection(dataProvider).indexOfId(id);

      selectedIndex = index;

      return index;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////

    public function axRecallLastSelection():int {
      return axSelectItemWithId(_lastSelectedId);
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////

    public function axAddItem(value:Object, selectNewItem:Boolean = true):int {
      var result:int = -1;

      if (dataProvider is ModelsCollection) {
        ModelsCollection(dataProvider).addItem(value);
        selectedItem = value;
        result = ModelsCollection(dataProvider).getItemIndex(value);
      }
      return result;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////

    public function axReplaceSelectedItem(newItem:Object):void {
      axReplaceItem(selectedItem, newItem);
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////

    public function axReplaceItem(oldItem:Object, newItem:Object):void {
      var modelsCollection:ModelsCollection;
      var refreshSelection:Boolean;

      if (dataProvider is ModelsCollection) {

        modelsCollection = ModelsCollection(dataProvider);
        refreshSelection = (selectedItem == oldItem);

        if ((AxDSUtils.replaceModelCollectionItem(modelsCollection, oldItem, newItem) != -1) && (refreshSelection)) {
          selectedItem = newItem;
        }
      }
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////

    public function axRemoveItem(value:Object):void {
      var result:Object = null;

      if (dataProvider is ModelsCollection) {
//        var lenght:int = (dataProvider as ModelsCollection).length;
//
//        if (selectedItem == value) {
//          if (selectedIndex < lenght - 1) {
//            selectedIndex += 1;
//          } else if (selectedIndex > 0) {
//            selectedIndex -= 1;
//          } else {
//            selectedIndex = -1;
//          }
//        }
        (dataProvider as ModelsCollection).removeItem(value);
        result = selectedItem;
      }
//      return result;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////

    public function axRemoveItemWithId(value:String):void {
//      var result:Object = null;

//      if (dataProvider is ModelsCollection) {
//        var lenght:int = (dataProvider as ModelsCollection).length;
//
//        if (selectedItem && (RxModel(selectedItem).id == value)) {
//          if (selectedIndex < lenght - 1) {
//            selectedIndex += 1;
//          } else if (selectedIndex > 0) {
//            selectedIndex -= 1;
//          } else {
//            selectedIndex = -1;
//          }
//        }
//
      if (dataProvider is ModelsCollection) {

        var it:Object = axItemWithId(value);

        if (it)
          ModelsCollection(dataProvider).removeItem(it);

//        result = selectedItem;
      }
//      return result;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////

    public function axItemWithId(value:String):Object {
      var item:Object;
      for (var i:int = 0; i < (dataProvider as ModelsCollection).length; i++) {
        item = ModelsCollection(dataProvider).getItemAt(i);
        if (RxModel(item).id == value)
          return item;
      }
      return null;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////

    public function axAdjustColumnWidthts(ignoreMinConstrain:Boolean = false):void {
      var netWidth:int = width - 30;
      var newWidth:int = 0;
      var noMaxWidthColIndex:Array = new Array;
      var noMaxWidthColValue:Array = new Array;
      var noMaxWidthSum:int = 0;

      var newWidhts:Array = new Array;

      var widthPercent:int;
      var widthMin:int;
      var widthMax:int;

      var col:AxDataGridColumn;

      if (!fNeedColumsWidthAdjust)
        return;

      for (var i:int = 0; i < columns.length; i++) {
        if (columns[i] is AxDataGridColumn) {
          col = (columns[i] as AxDataGridColumn);

          widthPercent = AxUtils.stringToInt(col.axWidthPercent, int(100 / columns.length));
          widthMin = AxUtils.stringToInt(col.axMinWidth, -1);
          widthMax = AxUtils.stringToInt(col.axMaxWidth, -1);

          newWidth = int((width * widthPercent) / 100);

          if (!ignoreMinConstrain) {
            if ((widthMin != -1) && (newWidth < widthMin))
              newWidth = widthMin;
          }
          if ((widthMax != -1) && (col.width > widthMax))
            newWidth = widthMax;

          netWidth = netWidth - newWidth;

          if (widthMax == -1) {
            noMaxWidthColIndex.push(i);
            noMaxWidthColValue.push(newWidth);
            noMaxWidthSum = noMaxWidthSum + newWidth;
          }

          newWidhts.push(newWidth); //  col.width = newWidth;
        }
      }

      if ((ignoreMinConstrain) || (netWidth == 0)) {

        for (var m:int = 0; m < columns.length - 1; m++) {

          if (columns[m] is AxDataGridColumn) {

            col = (columns[m] as AxDataGridColumn);
            col.width = newWidhts[m];
          }
        }

        return;
      }

      if (netWidth < 0) {
        axAdjustColumnWidthts(true);
      } else if (netWidth > 0) {
        var rest:int = netWidth;
        var percent:int = 0;
        var gain:int;
        var k:int;

        for (var j:int = 0; j < (noMaxWidthColIndex.length - 1); j++) {
          k = noMaxWidthColIndex[j];
          col = columns[k];
          percent = int((col.width * 100) / noMaxWidthSum);
          gain = int((percent * netWidth) / 100);
          newWidhts[k] = newWidhts[k] + gain; // col.width = col.width + gain; 
          netWidth = netWidth - gain;
        }

        k = noMaxWidthColIndex[noMaxWidthColIndex.length - 1];
        newWidhts[k] = newWidhts[k] + netWidth; //  col = columns[k]; col.width = col.width + netWidth;  
        netWidth = 0;

        for (var n:int = 0; n < columns.length - 1; n++) {

          if (columns[n] is AxDataGridColumn) {

            col = (columns[n] as AxDataGridColumn);
            col.width = newWidhts[n];
          }
        }

        fNeedColumsWidthAdjust = false;
      }
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////

    private function memorizeLastSelection():void {
      if ((selectedItem) && (dataProvider is ModelsCollection)) {
        _lastSelectedId = (RxModel(selectedItem)).id;
        _lastSelectedIndex = selectedIndex;
      }

      dispatchEvent(new AxListEvent(AxListEvent.SELECTION_CHANGE));
    }

  }
}